package com.rogo.mini.core
{
	import flash.display.Graphics;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.geom.Point;
	
	public class VisualElement implements IVisualElement, IInvalidate, IEventDispatcher
	{
		public function VisualElement()
		{
		}
		
		//--------------------------------------------------------------------------
		//
		//  Properties
		//
		//--------------------------------------------------------------------------
		
		private var initialized:Boolean = false;
		private var invalidateFlag:Boolean = false;
		
		//----------
		// s
		//----------
		
		private var _s:Sprite;
		
		public function get s():Sprite
		{
			if (!_s)
				_s = new Sprite();
			
			return _s;
		}
		
		//----------
		// graphics
		//----------
		
		public function get graphics():Graphics
		{
			return s.graphics;
		}
		
		//----------
		// x
		//----------
		
		private var _x:Number;

		public function get x():Number
		{
			return _x;
		}

		public function set x(value:Number):void
		{
			if (_x != value)
			{
				_x = value;
				
				s.x = x;
			}
		}

		//----------
		// y
		//----------
		
		private var _y:Number;

		public function get y():Number
		{
			return _y;
		}

		public function set y(value:Number):void
		{
			if (_y != value)
			{
				_y = value;
				
				s.y = y;
			}
		}

		//----------
		// width
		//----------
		
		private var _width:Number;

		public function get width():Number
		{
			return isNaN(_width) ? 0 : _width;
		}

		public function set width(value:Number):void
		{
			if (_width != value)
			{
				_width = value;
				
				invalidateProperties();
				invalidateSize();
				invalidateDisplayList();
			}
			
		}

		//----------
		// height
		//----------
		
		private var _height:Number;

		public function get height():Number
		{
			return isNaN(_height) ? 0 : _height;
		}

		public function set height(value:Number):void
		{
			
			if (_height != value)
			{
				_height = value;
				
				invalidateProperties();
				invalidateSize();
				invalidateDisplayList();
			}
		}
		
		//--------------------------------------------------------------------------
		//
		//  Methods
		//
		//--------------------------------------------------------------------------

		protected function updateElement():void
		{
		}
		
		protected function updateProperties():void
		{
		}
		
		protected function updateSize():void
		{
		}
		
		protected function updateDisplayList():void
		{
		}
		
		/**
		 * 将全局坐标点转换为本地坐标
		 * 
		 * @param point
		 * @return 
		 */		
		public function globalToLocal(point:Point):Point
		{
			return s.globalToLocal(point);
		}
		
		/**
		 * 将本地坐标点转换为全局坐标
		 * 
		 * @param point
		 * @return 
		 */
		public function localToGlobal(point:Point):Point
		{
			return s.localToGlobal(point);
		}
		
		//--------------------------------------------------------------------------
		//
		//  IVisualElement Methods
		//
		//--------------------------------------------------------------------------
		
		public function initialize():void
		{
			if (initialized)
				return;
			
			initialized = true;
			
			updateElement();
			
			invalidateProperties();
			invalidateSize();
			invalidateDisplayList();
		}
		
		public function addElement(element:IVisualElement):IVisualElement
		{
			s.addChild(element.s);
			element.initialize();
			return element;
		}
		
		public function addElementAt(element:IVisualElement, index:int):IVisualElement
		{
			s.addChildAt(element.s, index);
			element.initialize();
			return element;
		}
		
		public function removeElement(element:IVisualElement):IVisualElement
		{
			s.removeChild(element.s);
			return element;
		}
		
		public function removeElementAt(index:int):IVisualElement
		{
			return s.removeChildAt(index) as IVisualElement;
		}
		
		//--------------------------------------------------------------------------
		//
		//  Invalidate Mech
		//
		//--------------------------------------------------------------------------
		
		private var invalidatePropertiesFlag:Boolean = false;
		
		public function invalidateProperties():void
		{
			invalidatePropertiesFlag = true;
			invalidate();
		}
		
		private function validateProperties():void
		{
			if (invalidatePropertiesFlag)
			{
				updateProperties();
				invalidatePropertiesFlag = false;
			}
		}
		
		private var invalidateSizeFlag:Boolean = false;
		
		public function invalidateSize():void
		{
			invalidateSizeFlag = true;
			invalidate();
		}
		
		private function validateSize():void
		{
			if (invalidateSizeFlag)
			{
				updateSize();
				invalidateSizeFlag = false;
			}
		}
		
		private var invalidateDisplayListFlag:Boolean = false;
		
		public function invalidateDisplayList():void
		{
			invalidateDisplayListFlag = true;
			invalidate();
		}
		
		private function validateDisplayList():void
		{
			if (invalidateDisplayListFlag)
			{
				updateDisplayList();
				invalidateDisplayListFlag = false;
			}
		}
		
		/**
		 * invalidate 
		 */		
		public function invalidate():void
		{
			if (invalidateFlag)
				return;
			
			if (!invalidateFlag && s.stage)
			{
				invalidateFlag = true;
				s.addEventListener(Event.RENDER, renderDelayHandler);
				s.addEventListener(Event.ENTER_FRAME, renderDelayHandler);
				s.stage.invalidate();
			}
		}
		
		public function validate():void
		{
			invalidateFlag = false;
			
			s.removeEventListener(Event.RENDER, renderDelayHandler);
			s.removeEventListener(Event.ENTER_FRAME, renderDelayHandler);
			
			validateProperties();
			validateSize();
			validateDisplayList();
		}
		
		
		//--------------------------------------------------------------------------
		//
		//  IEventDispatcher Methods
		//
		//--------------------------------------------------------------------------
		
		public function addEventListener(type:String, 
										 listener:Function, 
										 useCapture:Boolean = false, 
										 priority:int = 0,
										 useWeakReference:Boolean = false):void
		{
			s.addEventListener(type, listener, useCapture, priority, useWeakReference);
		}
		
		public function dispatchEvent(event:Event):Boolean
		{
			return s.dispatchEvent(event);
		}
		
		
		//--------------------------------------------------------------------------
		//
		//  Event Handlers
		//
		//--------------------------------------------------------------------------
		
		private function renderDelayHandler(e:Event):void
		{
			validate();
		}
		
	}
}